package com.rongx.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.rongx.reggie.common.BaseContext;
import com.rongx.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 登录检查过滤器：全局拦截请求，校验用户（员工/普通用户）登录状态，未登录则拦截，已登录/白名单路径则放行
 * @ WebFilter：注册过滤器到Spring容器，拦截所有请求（/*）
 * filterName：过滤器唯一标识；urlPatterns：拦截范围（/*表示所有请求）
 */
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
@Slf4j // Lombok注解，自动生成日志对象log，用于打印请求日志
public class LoginCheckFilter implements Filter {

    /**
     * 路径匹配器：Spring提供，支持通配符（如/**匹配多级路径）
     * 用于判断请求路径是否在白名单，static final确保全局唯一，避免重复创建
     */
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    /**
     * 过滤器核心方法：所有拦截的请求都会进入，实现登录校验逻辑
     * @param servletRequest 原生请求对象（转HttpServletRequest获取HTTP特性）
     * @param servletResponse 原生响应对象（转HttpServletResponse操作响应）
     * @param filterChain 过滤器链：用于放行请求到下一级（过滤器/Controller）
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 1. 类型转换：转为HTTP专属对象，获取请求路径、Session等信息
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 2. 获取当前请求URI（如：/employee/login、/front/index.html）
        String requestURI = request.getRequestURI();
        log.info("拦截到请求requestURI:{}", requestURI); // 打印请求日志，便于调试

        // 3. 定义无需登录的白名单路径：未登录用户可访问的资源（登录接口、静态资源等）
        String[] urls = new String[]{
                "/employee/login",    // 员工登录接口
                "/employee/logout",   // 员工登出接口
                "/backend/**",        // 后台静态资源（JS/CSS/HTML）
                "/front/**",          // 前台静态资源
                "/common/**",         // 通用资源接口（如图片上传）
                "/",                  // 系统根路径
                "/user/sendMsg",      // 普通用户验证码发送接口
                "/user/login"         // 普通用户登录接口
        };

        // 4. 判断当前请求是否在白名单：调用check方法匹配路径
        boolean check = check(urls, requestURI);
        // 白名单路径直接放行，不做登录校验
        if (check) {
            log.info("直接放行✅，请求路径：{}", requestURI);
            filterChain.doFilter(request, response); // 放行请求
            return; // 结束当前逻辑，避免后续执行
        }

        // 5. 校验普通用户登录状态：Session中存在"user"表示已登录
        if (request.getSession().getAttribute("user") != null) {
            log.info("普通用户已登录，用户id为：{}", request.getSession().getAttribute("user"));
            // 保存用户ID到上下文（BaseContext含ThreadLocal，供后续业务使用）
            Long userId = (Long) request.getSession().getAttribute("user");
            BaseContext.setCurrentId(userId);
            filterChain.doFilter(request, response); // 放行已登录用户
            return;
        }

        // 6. 校验员工登录状态：Session中存在"employee"表示已登录
        if (request.getSession().getAttribute("employee") != null) {
            log.info("员工已登陆，员工ID：{}", request.getSession().getAttribute("employee"));
            // 保存员工ID到上下文，供后续业务（如记录操作人）使用
            Long empId = (Long) request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);
            filterChain.doFilter(request, response); // 放行已登录员工
            return;
        }

        // 7. 未登录处理：拦截请求，返回"NOTLOGIN"提示（前端据此跳登录页）
        log.info("用户未登录，拦截请求：{}", requestURI);
        // 返回JSON格式结果：R是统一返回类，error表示错误状态，"NOTLOGIN"是未登录标识
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));

    }

    /**
     * 路径匹配方法：判断当前请求路径是否在白名单中
     * @param urls 白名单路径数组
     * @param requestURI 当前请求路径
     * @return true：在白名单；false：不在白名单（需校验登录）
     */
    private boolean check(String[] urls, String requestURI) {
        for (String url : urls) {
            // 通配符匹配（如/backend/**匹配/backend/js/login.js）
            boolean isMatch = PATH_MATCHER.match(url, requestURI);
            if (isMatch) {
                return true; // 匹配成功，立即返回
            }
        }
        return false; // 无匹配，不在白名单
    }
}